package com.liuxing.javaSpringBoot.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * Created by IntelliJ IDEA.
 * -- 打印request控制信息
 * -- 打印指定方法调用执行时间
 * @File MyAOP.java
 * @Auth liuxing
 * @Date 2021/8/23 14:02
 * @Email liuxing997@foxmail.com
 */
@Aspect
@Component
public class MyAop {

    /**
     * -关联在方法上的切点，大面积额切入，支持与或非逻辑运算符
     * -第一个 * 代表返回类型不限
     * -第二个 * 代表 module 下所有子包
     * -第三个 * 代表所有类
     * -第四个 * 代表所有方法
     * (..) 代表参数不限
     * Order 代表优先级，数字越小优先级越高
     */

    private final static Logger LOGGER = LoggerFactory.getLogger(MyAop.class);

    @Pointcut("execution(public * com.liuxing.javaSpringBoot.modules.*.controller.*.*(..))")
    @Order(value = 1)
    public void controllerJoinPoint() { }

    //注解精确切点
    @Pointcut("@annotation(com.liuxing.javaSpringBoot.aop.MethodCallTimeAnnotation)")
    @Order(value = 1)
    public void methodCallTimeAnnotation(){

    }

    @Before(value = "controllerJoinPoint()")
    public void beforeController(JoinPoint joinPoint){
        LOGGER.debug("====== Before Controller ======");
    }

    //控制器切面环绕通知
    @Around(value = "controllerJoinPoint()")
    public Object aroundController(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        LOGGER.debug("====== Around Controller ======");
        ServletRequestAttributes servletRequestAttributes =
                (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        LOGGER.debug(String.format("RemoteAddr: %s",request.getRemoteAddr()));
        LOGGER.debug(String.format("RequestURI: %s",request.getRequestURI()));
        LOGGER.debug(String.format("Method: %s",request.getMethod()));
        LOGGER.debug(String.format("Class: %s",proceedingJoinPoint.getTarget().getClass()));
        LOGGER.debug(String.format("Signature: %s",proceedingJoinPoint.getSignature()));
        LOGGER.debug(String.format("Args: %s",proceedingJoinPoint.getArgs() == null ? "" : proceedingJoinPoint.getArgs()));
        return proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs()) ;
    }

    @After(value = "controllerJoinPoint()")
    public void afterController(JoinPoint joinPoint){
        LOGGER.debug("====== After Controller ======");
    }

    //注解切面通知
    @Around(value = "methodCallTimeAnnotation()")
    public Object aroundAnnotation(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        LOGGER.debug("====== Around Annotation ======");
        long start =  System.currentTimeMillis();
        Object obj = proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
        long end =  System.currentTimeMillis();
        LOGGER.debug(String.format("CallMethodTime: %s ms",(end - start)));
        return obj;
    }
}
